home *** CD-ROM | disk | FTP | other *** search
/ AGA Toolkit '97 / The AGA Toolkit '97.iso / programming / c / smc2cweb / src / c2cweb.w < prev    next >
Encoding:
Text File  |  1996-09-07  |  37.7 KB  |  1,275 lines

  1. % This is the cweb file c2cweb Version 1.4  20-Aug-1994
  2. %
  3. % You should process this file with
  4. %
  5. %           cweave +ai c2cweb.w
  6.  
  7. \pageno=\contentspagenumber \advance\pageno by 1
  8. \let\maybe=\iftrue
  9. \fullpageheight=240mm
  10. \pageheight=223mm
  11. \pagewidth=158mm
  12. \setpage
  13. \frenchspacing
  14. \def\in{\leavevmode\vrule width 0pt\nobreak\hskip 2em\hskip 0pt} % indentation
  15. \font\sixrm=cmr6
  16. \def\tm{$^{\hbox{\sixrm TM}}$} % trademark
  17.  
  18. \def\title{c2cweb (Version 1.4)}
  19.  
  20. \def\topofcontents{
  21.   \null\vfill
  22.   \centerline{\titlefont The {\ttitlefont c2cweb} program}
  23.   \vskip 20pt
  24.   \centerline{(Version 1.4)}
  25.   \vfill}
  26.  
  27. \def\botofcontents{
  28.   \vfill
  29.   \noindent
  30.   Copyright \copyright\ 1994 by Werner Lemberg
  31.   \bigskip\noindent
  32.   Permission is granted to make and distribute verbatim copies of this
  33.   document provided that the copyright notice and this permission notice
  34.   are preserved on all copies.
  35.  
  36.   \smallskip\noindent
  37.   Permission is granted to copy and distribute modified versions of this
  38.   document under the conditions for verbatim copying, provided that the
  39.   entire resulting derived work is distributed under the terms of a
  40.   permission notice identical to this one.}
  41.  
  42.  
  43.  
  44. @* Introduction.
  45. This is the \.{c2cweb} program by Werner Lemberg
  46. (\.{a7621gac@@awiuni11.bitnet}).
  47.  
  48. The ``banner line'' defined here should be changed whenever \.{c2cweb} is
  49. modified.
  50.  
  51. @d banner "\nThis is c2cweb Version 1.4  (c) 1994 by Werner Lemberg\n\n"
  52.  
  53. @
  54. \.{c2cweb} will transform ordinary \CEE/ or \CPLUSPLUS/ source code into
  55. \.{CWEB} formatted code. Three primary functions are performed: inserting
  56. \.{@@}--commands between code blocks, transforming comments into \TeX--text,
  57. and replacing offending characters like \.{\\}, \.{\_}, \.{\&} etc. with
  58. commands \TeX\ (and \.{CWEB}) can understand.
  59.  
  60. The only changes the user has to do normally is to insert `\.{/*@@@@*/}' or
  61. `\.{/*@@*/}' \\{starting a line} outside of a comment or string (the rest of
  62. these lines will be ignored).
  63.  
  64. \advance\leftskip by 3em
  65.  
  66.     \item{$\bullet$} \.{/*@@@@*/} starts a new section and switches
  67.     the function block algorithm on (see below).
  68.  
  69.     \item{$\bullet$} \.{/*@@*/} starts a new section and switches the
  70.     function block algorithm off. This is the default when \.{c2cweb} begins to
  71.     scan a file.
  72.  
  73. \advance\leftskip by -3em
  74.  
  75. Both `commands' will be suppressed in the output (two additional commands are
  76. described in the `Hints and Tricks'--section).
  77.  
  78. @
  79. Normal \CEE/ code consists of two parts: the code before function blocks
  80. (\.{\#include} and \.{\#define} statements, prototypes, structure definitions,
  81. global variables, etc.) and the function blocks (i.e. \.{foo()\{ ... \}})
  82. itselves (possibly mixed with global definitions of variables, structures
  83. etc.). The main reason to separate them are memory constraints of
  84. \.{CWEAVE}, and after \.{/*@@@@*/} each function block is written into an own
  85. section.
  86.  
  87. In header files, nothing is to do because there are no function blocks. In
  88. \CEE/ code files, it's usually sufficient to insert \.{/*@@@@*/} once, but
  89. you can structure your code further by inserting \.{/*@@*/} (and \.{/*@@@@*/}
  90. if necessary). See also the example file delivered with this package.
  91.  
  92. You will need a special \.{CWEAVE} executable (change files for \.{cweave.w}
  93. and \.{common.w} are included in this package) which has an enhanced
  94. preprocessor command handling, two additional control codes and can produce two
  95. different output formats.
  96.  
  97. See also the section `Hints and Tricks'.
  98.  
  99.  
  100. @* The program.
  101. The use of |_response()|, |_wildcard()|, and |_getname()| is compiler
  102. specific. If you don't use emx--gcc, it's likely that you have to use
  103. different functions. If you use this program under DOS, consider the 
  104. \UNIX/--like behavior of the ``|*|''--wildcard character.
  105.  
  106. After processing the options, the global variable |optind| (defined in
  107. \.{getopt.h}) is the index to the first file name.
  108.  
  109. @d FALSE 0
  110. @d TRUE  1
  111. @d DONE  2
  112. @d WAIT  3
  113.  
  114. @c
  115. @<Include files@>;
  116. @<Prototypes@>;
  117. @<Global variables@>;@#
  118.  
  119. void main(argc, argv)
  120.   int argc;
  121.   char *argv[];
  122.  
  123.    {int i;
  124.     char buffer[DIR_LENGTH + FILE_NAME_LENGTH + 1];
  125.     char *p, *q;
  126.  
  127.  
  128.     printf(banner);@#
  129.  
  130. #ifdef __EMX__
  131.     _response(&argc, &argv); /* to expand response files */
  132.     _wildcard(&argc, &argv); /* to expand wildcards */
  133. #endif@#
  134.  
  135.     @<Get command switches@>;@#
  136.  
  137.     if(optind == argc)
  138.         usage();@#
  139.  
  140.     for(i = optind; i < argc - 1; i++)
  141.        {printf("  processing %s\n", argv[i]);@#
  142.  
  143.         open_files(argv[i]);
  144.         q = protect_underlines(_getname(argv[i]));
  145.         if((p = strrchr(q, '.')) != NULL)
  146.                          /* the macro \.{\\ZZZ} suppresses the final dot after
  147.                             the section title if the filename contains a dot */
  148.             fprintf(out,@/
  149.             "@@*{%s\\ZZZ{\\setbox0=\\hbox{%s}\\hskip-\\wd0}}.\n"@/
  150.             "\\ind=2\n\n", q, p);
  151.         else
  152.             fprintf(out, "@@*{%s}.\n"@/
  153.             "\\ind=2\n\n", q);@#
  154.  
  155.         handle_input();
  156.         fclose(in);
  157.         fclose(out);
  158.        }@#
  159.  
  160.     printf("  processing %s\n", argv[i]);@#
  161.  
  162.     open_files(argv[i]); /* the `master' file */
  163.     @<Write limbo@>;
  164.     q = protect_underlines(_getname(argv[i]));
  165.     if((p = strrchr(q, '.')) != NULL)
  166.         fprintf(out,@/
  167.         "@@*{%s\\ZZZ{\\setbox0=\\hbox{%s}\\hskip-\\wd0}}.\n"@/
  168.         "\\ind=2\n\n", q, p);
  169.     else
  170.         fprintf(out, "@@*{%s}.\n"@/
  171.         "\\ind=2\n\n", q);@#
  172.  
  173.     handle_input();
  174.     @<Write index section@>;@#
  175.  
  176.     strcpy(buffer, argv[argc - 1]);
  177.     modify_filename(buffer);@#
  178.  
  179.     printf(@/
  180.     "\n You must now call CWEAVE with %s%s\n"@/
  181.     " as the argument to get a TeX output", outdir, _getname(buffer));
  182.     if(optind < argc - 1)
  183.         printf(" of all processed files");
  184.     printf("\n");@#
  185.  
  186.     fclose(in);
  187.     fclose(out);
  188.    }
  189.  
  190. @
  191. \.{getopt.h} contains the \UNIX/--specific |getopt()|. If your system doesn't
  192. support this function, get the GNU \CEE/--library for an implementation.
  193.  
  194. @<Include files@>=
  195. #include <ctype.h>
  196. #include <getopt.h>
  197. #include <stdio.h>
  198. #include <stdlib.h>
  199. #include <string.h>
  200.  
  201.  
  202. @*1 The input switches.
  203. If the switch \.{-v} is set, all comments are written in typewriter type;
  204. comments starting a line will also start a line in the output.
  205.  
  206. All tabs will be expanded, and the \.{-t} switch defines the tab length
  207. (default value is 4).
  208.  
  209. The switch \.{-l} causes all linefeeds inside of \CEE/--text to be output
  210. explicitly by inserting a \.{@@/} command at the end of each code line.
  211.  
  212. The output directory will be set with the \.{-o} option; this directory must
  213. already exist. Probably you have to adjust |PATH_SEPARATOR| and
  214. |pathsepchar[]| to your operating system.
  215.  
  216. To get a title, use the \.{-b} switch with the titlestring enclosed in double
  217. quotes; this string will be passed directly to \TeX.
  218.  
  219. One--sided output is enabled with the option \.{-1} set.
  220.  
  221. The global variable |optarg| (defined in \.{getopt.h}) points to the option
  222. argument; the string |optswchar[]| is modified to allow |'-'| and |'/'| as
  223. characters which start options (not under \UNIX/).
  224.  
  225. @d DIR_LENGTH 80
  226. @d TITLE_LENGTH 100
  227. @d PATH_SEPARATOR '/'
  228.  
  229. @<Global...@>=
  230. int tab_length = 4;
  231. int verbatim = FALSE;
  232. int user_linefeed = FALSE;
  233. int one_side = FALSE;
  234. char outdir[DIR_LENGTH + 1];
  235. char title[TITLE_LENGTH + 1];@#
  236.  
  237. #ifdef __EMX__
  238. char optchar[] = "-/";
  239. char pathsepchar[] = "\\/";
  240. #else
  241. char optchar[] = "-";
  242. char pathsepchar[] = "/";
  243. #endif
  244.  
  245. @
  246. @<Get command switches@>=
  247.    {char c;
  248.     int i;
  249.  
  250.  
  251.     outdir[0] = '\0';
  252. #ifdef __EMX__
  253.     optswchar = optchar;
  254. #endif@#
  255.  
  256.     strcpy(title, "c2cweb output"); /* the default title */@#
  257.  
  258.     while((c = getopt(argc, argv, "b:lo:t:v1")) != EOF)
  259.        {switch(c)
  260.            {case 'b':
  261.                 if(strchr(optchar, optarg[0]))
  262.                                            /* check if argument is an option */
  263.                     usage();@#
  264.  
  265.                 if(strlen(optarg) >= TITLE_LENGTH)
  266.                     fprintf(stderr,@/
  267.                     "\nTitle too long. Will use \"c2cweb output\".\n");
  268.                 else
  269.                     strcpy(title, optarg);
  270.                 break;
  271.             case 'l':
  272.                 user_linefeed = TRUE;
  273.                 break;
  274.             case 'o':
  275.                 if(strchr(optchar, optarg[0]))
  276.                     usage();@#
  277.  
  278.                 if((i = strlen(optarg)) >= DIR_LENGTH)
  279.                     fprintf(stderr,@/
  280.                     "\nOutput directory name too long. Will be ignored.\n");
  281.                 else
  282.                    {strcpy(outdir, optarg);
  283.                     if(!strchr(pathsepchar, outdir[i - 1]))
  284.                               /* check if last character is a path separator */
  285.                        {outdir[i] = PATH_SEPARATOR;
  286.                         outdir[i + 1] = '\0';
  287.                        }
  288.                    }
  289.                 break;
  290.             case 't':
  291.                 if(strchr(optchar, optarg[0]))
  292.                     usage();@#
  293.  
  294.                 tab_length = atoi(optarg);
  295.                 if(tab_length == 0 || tab_length > 8)
  296.                     tab_length = 4; /* default value */
  297.                 break;
  298.             case 'v':
  299.                 verbatim = TRUE;
  300.                 break;
  301.             case '1':
  302.                 one_side = TRUE;
  303.                 break;
  304.             default:
  305.                 usage();
  306.                 break;
  307.            }
  308.        }
  309.    }
  310.  
  311. @
  312. The output file has the same name as the input file but a different extension:
  313. it will append a \.{w} or, if the extension is three characters long,
  314. substitute the third character with a \.{w}, i.e. \.{.c} becomes \.{.cw},
  315. \.{.h} becomes \.{.hw}, \.{.cpp} will be replaced by \.{.cpw} and so on
  316. (notice that for example \.{.cppp} also becomes \.{.cpw}). If the character to
  317. be changed is a \.{w}, an \.{x} is used instead of. This will be done by the
  318. function |modify_filename()|.
  319.  
  320. @d FILE_NAME_LENGTH 80
  321.  
  322. @<Global...@>=
  323.     FILE *in, *out;
  324.  
  325. @
  326. @<Prototypes@>=
  327. void open_files(char *);
  328.  
  329. @
  330. @c
  331. void open_files(filename)
  332.   char *filename;
  333.    {char buffer[DIR_LENGTH + FILE_NAME_LENGTH + 1];
  334.  
  335.  
  336.     if(strlen(filename) > FILE_NAME_LENGTH - 2)
  337.        {fprintf(stderr, "\n  File name too long.\n");
  338.         exit(-1);
  339.        }@#
  340.  
  341.     if((in = fopen(filename, "rt")) == NULL)
  342.        {fprintf(stderr, "\n  Can't open input file %s\n", filename);
  343.         exit(-1);
  344.        }@#
  345.  
  346.     strcpy(buffer, outdir);
  347.     strcat(buffer, filename);
  348.     modify_filename(buffer);@#
  349.  
  350.     if((out = fopen(buffer, "wt")) == NULL)
  351.        {fprintf(stderr, "\n  Can't open output file %s\n", buffer);
  352.         exit(-1);
  353.        }
  354.    }
  355.  
  356.  
  357. @*1 The output header.
  358. This is the header of the last output file. You must call \.{CWEAVE} with this
  359. file as an argument --- all other processed files will be included.
  360.  
  361. Additionally this `master' file will include the file \.{compiler.w}, which
  362. should contain all system dependent definitions (like \.{va\_decl} or
  363. \.{va\_arg}) not contained in the \.{CWEAVE} program. The syntax of
  364. \.{compiler.w} is \.{CWEB} syntax; please read the documentation if you have
  365. questions. You should set the global variable |CWEBINPUTS| used by \.{CWEAVE}
  366. (and \.{CTANGLE}) to the directory where \.{compiler.w} resides.
  367.  
  368. The function |_getname()| will accept forward and backward slashes as path
  369. separators if you compile under emx. However, options can be introduced with
  370. |'-'| and |'/'|, therefore paths starting with a forward slash must be enclosed
  371. in double quotes (not under \UNIX/).
  372.  
  373. @<Write limbo@>=
  374.     fprintf(out,@/
  375.         "\\font\\symb=cmsy10\n"@/
  376.         "\\font\\math=cmmi10\n"@/
  377.         "\\def\\ob"@/
  378.             "{\\parskip=0pt\\parindent=0pt%%\n"@/
  379.             "\\let\\\\=\\BS\\let\\{=\\LB\\let\\}=\\RB\\let\\~=\\TL%%\n"@/
  380.             "\\let\\ =\\SP\\let\\_=\\UL\\let\\&=\\AM\\let\\^=\\CF%%\n"@/
  381.             "\\obeyspaces\\frenchspacing\\tt}\n"@/
  382.         "\n"@/
  383.         "\\def\\e{\\hfill\\break\\hbox{}}\n"@/
  384.         "\\def\\{{\\relax\\ifmmode\\lbrace\\else$\\lbrace$\\fi}\n"@/
  385.         "\\def\\}{\\relax\\ifmmode\\rbrace\\else$\\rbrace$\\fi}\n"@/
  386.         "\\def\\takenone#1{\\hskip-0.1em}\n"@/
  387.         "\\let\\ZZZ=\\relax\n"@/
  388.         "\n"@/
  389.         "%s"@/
  390.         "\n"@/
  391.         "\\pageno=\\contentspagenumber \\advance\\pageno by 1\n"@/
  392.         "\\let\\maybe=\\iftrue\n"@/
  393.         "\n"@/
  394.         "\\def\\title{%s}\n"@/
  395.         "\n"@/
  396.         "@@i compiler.w\n"@/
  397.         "\n", one_side ? "\\let\\lheader=\\rheader\n" : "", title);@#
  398.  
  399.     for(i = optind; i < argc - 1; i++)
  400.        {strcpy(buffer, argv[i]);
  401.         modify_filename(buffer);@#
  402.  
  403.         fprintf(out, "@@i %s\n", _getname(buffer));
  404.        }@#
  405.  
  406.     fputc('\n', out);@#
  407.  
  408.  
  409. @*1 Input Handling.
  410.  
  411. @d BUFFER_LENGTH 500
  412.  
  413. @<Prototypes@>=
  414. void handle_input(void);
  415.  
  416. @
  417. This is a wild hack. Perhaps in a future version I will improve it.
  418.  
  419. @<Global...@>=
  420. char buffer[BUFFER_LENGTH + 1];
  421.  
  422. @
  423. @d xisspace(c) (isspace(c) && ((unsigned char)c < 0200))
  424.  
  425. @c
  426. void handle_input(void)
  427.    {char *buf_p;
  428.     char ch;@#
  429.  
  430.     int any_input = FALSE;
  431.                  /* set after the first non blank character in a new section */
  432.     int brace_count = 0;
  433.     int blank_count = 0;@#
  434.  
  435.     int in_comment = FALSE;
  436.     int in_C = FALSE;
  437.     int in_string = FALSE;
  438.     int short_comment = FALSE;
  439.     int leading_blanks = TRUE;
  440.     int double_linefeed = FALSE; /* set if last character was a linefeed */
  441.     int linefeed_comment = FALSE;
  442.                           /* set if a comment follows a linefeed immediately */
  443.     int comment_slash = FALSE; /* set if last character was a slash */
  444.     int comment_star = FALSE; /* set if last character was a star */
  445.     int escape_state = FALSE;
  446.    /* needed to check whether in string or at the end of a preprocessor line */
  447.     int before_TeX_text = FALSE;@#
  448.  
  449.     int function_blocks = FALSE; /* set if function block algorithm is on */@#
  450.  
  451.  
  452.     line_number = 0;
  453.  
  454.     while(get_line())
  455.        {buf_p = buffer;@#
  456.  
  457.         do
  458.            {ch = *buf_p;@#
  459.  
  460.             @<Special cases@>;@#
  461.  
  462.             switch(ch)
  463.                {case ' ':
  464.                     if(leading_blanks)
  465.                        {blank_count++;
  466.                         goto end;
  467.                        }
  468.                     break;@#
  469.  
  470.                 case '\t':
  471.                        {int i = tab_length - (column % tab_length);
  472.  
  473.                         column += i - 1; /* we'll say later |column++| */@#
  474.  
  475.                         if(leading_blanks)
  476.                            {blank_count += i;
  477.                             goto end;
  478.                            }@#
  479.  
  480.                         while(i--)
  481.                             fputc(' ', out);
  482.                         goto end;
  483.                        }
  484.                     break;@#
  485.  
  486.                 case '{':
  487.                     @<Cases for |'{'|@>;
  488.                     break;@#
  489.  
  490.                 case '}':
  491.                     @<Cases for |'}'|@>;
  492.                     break;@#
  493.  
  494.                 case '/':
  495.                     @<Cases for |'/'|@>;
  496.                     break;@#
  497.  
  498.                 case '*':
  499.                     @<Cases for |'*'|@>;
  500.                     break;@#
  501.  
  502.                 case '\n':
  503.                     @<Cases for |'\n'|@>;
  504.                     break;@#
  505.  
  506.                 case '@@':
  507.                     @<Cases for |'@@'|@>;
  508.                     break;@#
  509.  
  510.                 case '\'':
  511.                     @<Cases for |'\''|@>;
  512.                     break;@#
  513.  
  514.                 case '\"':
  515.                     @<Cases for |'\"'|@>;
  516.                     break;@#
  517.  
  518.                 case '\\':
  519.                     @<Cases for |'\\'|@>;
  520.                     break;@#
  521.  
  522.                 default:
  523.                     @<Cases for |default|@>;
  524.                     break;
  525.                }@#
  526.  
  527.             fputc(ch, out);@#
  528.  
  529. end:
  530.             buf_p++;
  531.             column++;
  532.            } while(ch != '\n');
  533.        }
  534.    }
  535.  
  536. @
  537. Here comes a bunch of |if|--statements.
  538.  
  539. @<Special cases@>=
  540.         if(buf_p == buffer) /* start of a line */
  541.            {if(!(in_comment || in_string))
  542.                {if(!strncmp(buf_p, "/""*@@@@*""/", 6))
  543.                    {in_C = FALSE;
  544.                     before_TeX_text = TRUE;
  545.                     function_blocks = WAIT; /* switch on the algorithm */
  546.                     brace_count = 0;@#
  547.  
  548.                     if(any_input)
  549.                         fputs("\n@@\n"@/
  550.                               "\\ind=2\n\n", out); /* start a new section */@#
  551.  
  552.                     any_input = FALSE;
  553.                     *(buf_p--) = '\n';
  554.                                      /* the rest of the line will be ignored */
  555.                     goto end;
  556.                    }
  557.                 else if(!strncmp(buf_p, "/""*@@*""/", 5))
  558.                    {in_C = FALSE;
  559.                     before_TeX_text = TRUE;
  560.                     function_blocks = FALSE; /* switch off the algorithm */@#
  561.  
  562.                     if(any_input)
  563.                         fputs("\n@@\n"@/
  564.                               "\\ind=2\n\n", out);@#
  565.  
  566.                     any_input = FALSE;
  567.                     *(buf_p--) = '\n';
  568.                     goto end;
  569.                    }
  570.                 else if(!strncmp(buf_p, "/""*{*""/", 5))
  571.                    {brace_count++; /* a dummy opening brace */
  572.                     fputs("@@{\n", out);@#
  573.  
  574.                     ch = '\n'; /* an end of line is simulated */
  575.                     goto end;
  576.                    }
  577.                 else if(!strncmp(buf_p, "/""*}*""/", 5))
  578.                    {brace_count--; /* a dummy closing brace */
  579.                     fputs("@@}\n", out);@#
  580.  
  581.                     if(!brace_count && function_blocks)
  582.                                           /* end of function block reached ? */
  583.                        {in_C = FALSE;
  584.                         before_TeX_text = TRUE;@#
  585.  
  586.                         break;
  587.                        }@#
  588.  
  589.                     ch = '\n';
  590.                     goto end;
  591.                    }
  592.                }
  593.            }@#
  594.  
  595.         if(double_linefeed && ch == '/')
  596.             linefeed_comment = TRUE;@#
  597.  
  598.         if(double_linefeed && (ch == ' ' || ch == '\t'))
  599.             leading_blanks = TRUE;@#
  600.  
  601.         if(ch != '\n') /* multiple linefeed ? */
  602.             double_linefeed = FALSE;@#
  603.  
  604.         if(!xisspace(ch)) /* whitespaces ? */
  605.            {any_input = TRUE;@#
  606.  
  607.             if(before_TeX_text && function_blocks)
  608.                {before_TeX_text = FALSE;@#
  609.  
  610.                 if(function_blocks == WAIT)
  611.                     function_blocks = TRUE;
  612.                                            /* start at the second occurrence */
  613.                 else
  614.                    {fputs("@@\n"@/
  615.                           "\\ind=2\n\n", out); /* start a new text section */@#
  616.  
  617.                     if(leading_blanks)
  618.                        {leading_blanks = FALSE;@#
  619.  
  620.                         while(blank_count--)
  621.                             fputc(' ', out);
  622.                         blank_count = 0;
  623.                        }
  624.                    }
  625.                }@#
  626.  
  627.             if(in_comment && leading_blanks)
  628.                {leading_blanks = FALSE;@#
  629.  
  630.                 while(blank_count--)
  631.                     fputc(' ', out);
  632.                 blank_count = 0;
  633.                }
  634.            }@#
  635.  
  636.         if(!(ch == '/' || xisspace(ch)))
  637.                                 /* whitespace or possible start of comment ? */
  638.            {if(!(in_comment || in_C || comment_slash))  /* outside of code ? */
  639.                {in_C = TRUE;@#
  640.  
  641.                 fputs("@@c\n", out); /* start of a new code section */@#
  642.  
  643.                 if(leading_blanks)
  644.                    {leading_blanks = FALSE;@#
  645.  
  646.                     while(blank_count--)
  647.                         fputc(' ', out);
  648.                     blank_count = 0;
  649.                    }
  650.                }@#
  651.  
  652.             if(!(in_comment || comment_slash) && leading_blanks)
  653.                {leading_blanks = FALSE;@#
  654.  
  655.                 while(blank_count--)
  656.                     fputc(' ', out);
  657.                 blank_count = 0;
  658.                }
  659.            }@#
  660.  
  661.         if(comment_slash && !(ch == '*' || ch == '/'))
  662.                                                      /* start of a comment ? */
  663.            {comment_slash = FALSE;
  664.             if(!in_comment)
  665.                 linefeed_comment = FALSE;@#
  666.  
  667.             fputc('/', out);
  668.            }@#
  669.  
  670.         if(comment_star && ch != '/') /* end of a comment ? */
  671.            {comment_star = FALSE;@#
  672.  
  673.             fputc('*', out);
  674.            }@#
  675.  
  676.         if(escape_state && !(ch == '\"' || ch == '\n' || ch == '\\'))
  677.           /* end of string or end of preprocessor line or backslash itself ? */
  678.             escape_state = FALSE;@#
  679.  
  680. @
  681. @<Cases for |'{'|@>=
  682.                 if(in_comment)
  683.                     fputc('\\', out);
  684.                 else if(in_string)
  685.                     break;
  686.                 else if(function_blocks)
  687.                    {brace_count++;
  688.                     in_C = TRUE;
  689.                    }
  690.  
  691. @
  692. @<Cases for |'@@'|@>=
  693.                 if(in_comment)
  694.                    {fputs("{\\char64}", out);
  695.                     goto end;
  696.                    }
  697.                 else /* \.{CWEB} needs \.{@@@@} to output \.{@@} */
  698.                     fputc('@@', out);
  699.  
  700. @
  701. @<Cases for |'\''|@>=
  702.                 if(!in_comment)
  703.                    {if(*(buf_p + 1) == '\"' && *(buf_p + 2) == '\'')
  704.                         escape_state = TRUE;           /* this catches |'"'| */
  705.                    }
  706.  
  707. @
  708. @<Cases for |'\"'|@>=
  709.                 if(!in_comment) /* start or end of a string ? */
  710.                    {if(escape_state)
  711.                         escape_state = FALSE;
  712.                     else
  713.                         in_string = TRUE - in_string;
  714.                    }
  715.  
  716. @
  717. @<Cases for |'\\'|@>=
  718.                 if(in_comment)
  719.                    {fputs("{\\symb\\char110}", out);
  720.                     goto end;
  721.                    }
  722.                 else
  723.                     escape_state = TRUE - escape_state;
  724.                  /* continuation of preprocessor line or an escape character */
  725.  
  726. @
  727. @<Cases for |'}'|@>=
  728.                 if(in_comment)
  729.                     fputc('\\', out);
  730.                 else if(in_string)
  731.                     break;
  732.                 else if(function_blocks)
  733.                    {brace_count--;
  734.                     if(!brace_count) /* end of function block reached ? */
  735.                        {in_C = FALSE;@#
  736.  
  737.                         before_TeX_text = TRUE;
  738.                         break;
  739.                        }
  740.                    }
  741.  
  742. @
  743. @<Cases for |'/'|@>=
  744.                 if(comment_star)
  745.                    {comment_star = FALSE;
  746.                     leading_blanks = FALSE;@#
  747.  
  748.                     if(!short_comment)
  749.                        {in_comment = FALSE; /* end of comment */@#
  750.  
  751.                         if(!in_C)
  752.                            {linefeed_comment = FALSE;@#
  753.  
  754.                             if(verbatim)
  755.                                 fputs("*""/}", out);@#
  756.  
  757.                             if(*(buf_p + 1) == '\n') /* end of line ? */
  758.                                 fputs("\\e{}%", out);@#
  759.  
  760.                             goto end;
  761.                            }
  762.  
  763.                         if(in_C && verbatim)
  764.                            {if(linefeed_comment)
  765.                                {linefeed_comment = FALSE;@#
  766.  
  767.                                 fputs("*""/@@>", out);
  768.                                 if(*(buf_p + 1) == '\n' && !user_linefeed)
  769.                                     fputs("@@/", out);
  770.                                 goto end;
  771.                                }
  772.                             else
  773.                                 fputc('}', out);@#
  774.                            }@#
  775.  
  776.                         linefeed_comment = FALSE;@#
  777.  
  778.                         if(in_C || verbatim)
  779.                             fputc('*', out);
  780.                         else
  781.                             goto end;
  782.                        }
  783.                     else
  784.                         fputc('*', out);
  785.                    }
  786.                 else if(comment_slash)
  787.                    {comment_slash = FALSE;@#
  788.  
  789.                     if(!short_comment)
  790.                        {in_comment = TRUE;
  791.                         short_comment = TRUE; /* start of a short comment */@#
  792.  
  793.                         if(!in_C && verbatim)
  794.                            {fputs("{\\ob{}", out);
  795.                             if(leading_blanks)
  796.                                {leading_blanks = FALSE;@#
  797.  
  798.                                 while(blank_count--)
  799.                                     fputc(' ', out);
  800.                                 blank_count = 0;
  801.                                }
  802.                             fputs("//", out);@#
  803.  
  804.                             goto end;
  805.                            }@#
  806.  
  807.                         if(in_C && verbatim)
  808.                            {if(leading_blanks || linefeed_comment)
  809.                                {linefeed_comment = TRUE;@#
  810.  
  811.                                 if(!user_linefeed)
  812.                                     fputs("@@/", out);
  813.                                 fputs("@@t}\\8{\\ob{}", out);
  814.                                          /* this cryptic command starts a
  815.                                             comment line without indentation */
  816.                                 if(leading_blanks)
  817.                                    {leading_blanks = FALSE;@#
  818.  
  819.                                     while(blank_count--)
  820.                                         fputc(' ', out);
  821.                                     blank_count = 0;
  822.                                    }
  823.                                 fputs("//", out);
  824.                                }
  825.                             else
  826.                                 fputs("//{\\ob{}", out);@#
  827.  
  828.                             goto end;
  829.                            }@#
  830.  
  831.                         if(in_C || verbatim)
  832.                             fputc('/', out);
  833.                         else
  834.                             goto end;
  835.                        }
  836.                     else
  837.                         fputc('/', out);
  838.                    }
  839.                 else
  840.                    {comment_slash = TRUE;@#
  841.  
  842.                     goto end;
  843.                    }
  844.  
  845. @
  846. @<Cases for |'*'|@>=
  847.                 if(comment_slash)
  848.                    {comment_slash = FALSE;@#
  849.  
  850.                     if(in_comment && !short_comment)
  851.                                     /* aah, uuh, for people who `comment out'
  852.                                        code with comments instead of using
  853.                                        \.{\#if 0==1} and \.{\#endif} for
  854.                                        example --- this non--ANSI behaviour
  855.                                        would cause bad formatted code and is
  856.                                        therefore not supported; the program
  857.                                        exits */
  858.                        {fprintf(stderr,
  859.                         "    Error line %d: Nested comments not supported\n",
  860.                         line_number);
  861.                         exit(-1);
  862.                        }@#
  863.  
  864.                     if(!short_comment)
  865.                        {in_comment = TRUE; /* start of comment */@#
  866.  
  867.                         if(!in_C && verbatim)
  868.                            {fputs("{\\ob{}", out);
  869.                             if(leading_blanks)
  870.                                {leading_blanks = FALSE;@#
  871.  
  872.                                 while(blank_count--)
  873.                                     fputc(' ', out);
  874.                                 blank_count = 0;
  875.                                }
  876.                             fputs("/""*", out);@#
  877.  
  878.                             goto end;
  879.                            }@#
  880.  
  881.                         if(in_C && verbatim)
  882.                            {if(leading_blanks || linefeed_comment)
  883.                                {linefeed_comment = TRUE;
  884.  
  885.                                 if(!user_linefeed)
  886.                                     fputs("@@/", out);
  887.                                 fputs("@@t}\\8{\\ob{}", out);
  888.                                 if(leading_blanks)
  889.                                    {leading_blanks = FALSE;@#
  890.  
  891.                                     while(blank_count--)
  892.                                         fputc(' ', out);
  893.                                     blank_count = 0;
  894.                                    }
  895.                                 fputs("/""*", out);
  896.                                }
  897.                             else
  898.                                 fputs("/""*{\\ob{}", out);@#
  899.  
  900.                             goto end;
  901.                            }@#
  902.  
  903.                         if(in_C || verbatim)
  904.                             fputc('/', out);
  905.                         else
  906.                            {fputs("  ", out);@#
  907.  
  908.                             goto end;
  909.                            }
  910.                        }
  911.                     else
  912.                         fputc('/', out);
  913.                    }
  914.                 else
  915.                    {comment_star = TRUE;@#
  916.  
  917.                     goto end;
  918.                    }
  919.  
  920. @
  921. @<Cases for |'\n'|@>=
  922.                 blank_count = 0;@#
  923.  
  924.                 if(!in_comment && in_C)
  925.                    {if(double_linefeed == FALSE)
  926.                        {double_linefeed = TRUE;
  927.                         if(escape_state)
  928.                            {escape_state = FALSE;
  929.                                       /* continuation of a preprocessor line */
  930.                             leading_blanks = TRUE;@#
  931.  
  932.                             if(in_string)
  933.                                 fputc('\n', out);
  934.                             else
  935.                                 fputs("\n@@/", out);
  936.                             goto end;
  937.                            }@#
  938.  
  939.                         if(!leading_blanks && user_linefeed)
  940.                             fputs("@@/", out);
  941.                        }
  942.                     else if(double_linefeed == TRUE)
  943.                        {double_linefeed = DONE;
  944.                                   /* blank lines in the input will be output as
  945.                                      little white space between code lines */@#
  946.                         fputs("@@#", out);
  947.                        }
  948.                    }@#
  949.  
  950.                 leading_blanks = TRUE;@#
  951.  
  952.                 if(short_comment)
  953.                    {short_comment = FALSE;
  954.                     in_comment = FALSE;
  955.                     double_linefeed = TRUE;@#
  956.  
  957.                     if(verbatim)
  958.                        {if(linefeed_comment && in_C)
  959.                             fputs("@@>", out);
  960.                         else
  961.                             fputc('}', out);
  962.                        }@#
  963.  
  964.                     if(!in_C)
  965.                         fputs("\\e{}%", out);
  966.                     else if(linefeed_comment && verbatim)
  967.                         fputs("@@/", out);@#
  968.  
  969.                     linefeed_comment = FALSE;
  970.                    }@#
  971.  
  972.                 if(in_comment && in_C && verbatim && linefeed_comment)
  973.                    {fputs("@@>@@/\n@@t}\\8{\\ob{}", out);
  974.                        /* continuation of a comment line without indentation */
  975.                     goto end;
  976.                    }@#
  977.  
  978.                 if(in_comment && verbatim)
  979.      /* Both \.{CWEAVE} and \TeX\ need an input at the beginning of a line
  980.         to prevent leading blanks be swallowed while in verbatim mode;
  981.         this will be the macro \.{\\e} which causes a linebreak */
  982.                    {fputs("\n\\e{}", out);
  983.                     goto end;
  984.                    }
  985.  
  986. @
  987. All other special characters will be substituted with proper sequences \TeX\
  988. can understand.
  989.  
  990. @<Cases for |default|@>=
  991.                 if(in_comment)
  992.                    {switch(ch)
  993.                        {case '#':
  994.                             fputs("{\\#}", out);
  995.                             break;@#
  996.  
  997.                         case '$':
  998.                             fputs("{\\$}", out);
  999.                             break;@#
  1000.  
  1001.                         case '%':
  1002.                             fputs("{\\%}", out);
  1003.                             break;@#
  1004.  
  1005.                         case '&':
  1006.                             fputs("{\\AM}", out);
  1007.                             break;@#
  1008.  
  1009.                         case '_':
  1010.                             fputs("{\\_}", out);
  1011.                             break;@#
  1012.  
  1013.                         case '^':
  1014.                             fputs("{\\^{}}", out);
  1015.                             break;@#
  1016.  
  1017.                         case '\\':
  1018.                             fputs("{\\symb\\char110}", out);
  1019.                             break;@#
  1020.  
  1021.                         case '~':
  1022.                             fputs("{\\~{}}", out);
  1023.                             break;@#
  1024.  
  1025.                         case '|':
  1026.                             fputs("{\\symb\\char106}", out);
  1027.                             break;@#
  1028.  
  1029.                         case '<':
  1030.                             fputs("{\\math\\char60}", out);
  1031.                             break;@#
  1032.  
  1033.                         case '>':
  1034.                             fputs("{\\math\\char62}", out);
  1035.                             break;@#
  1036.  
  1037.                         default:
  1038.                             fputc(ch, out);
  1039.                             break;
  1040.                        }@#
  1041.  
  1042.                     goto end;
  1043.                    }
  1044.  
  1045. @
  1046. Because the index macros defined in \.{cwebmac.tex} don't append a dot, we have
  1047. to redefine \.{\\ZZZ}.
  1048.  
  1049. @<Write index section@>=
  1050.     fprintf(out,@/
  1051.             "\n"@/
  1052.             "@@*Index.\n"@/
  1053.             "\\let\\ZZZ=\\takenone\n");
  1054.  
  1055. @
  1056. @<Prototypes@>=
  1057. void usage(void);
  1058.  
  1059. @
  1060. @c
  1061. void usage(void)
  1062.    {fprintf(stderr,@/
  1063.     "Usage: c2cweb [switches] csourcefile(s) | @@responsefile(s)"@/
  1064.     "\n"@/
  1065.     "\n  possible switches:"@/
  1066.     "\n"@/
  1067.     "\n    -b \"title\"    set title"@/
  1068.     "\n    -l            use input linefeeds"@/
  1069.     "\n    -o dirname    set output directory (must already exist)"@/
  1070.     "\n    -t tablength  set tabulator length (default 4)"@/
  1071.     "\n    -v            verbatim mode"@/
  1072.     "\n    -1            one-sided output"@/
  1073.     "\n"@/
  1074.     "\n");@#
  1075.  
  1076.     exit(-1);
  1077.    }
  1078.  
  1079. @
  1080. @<Prototypes@>=
  1081. void modify_filename(char *);
  1082.  
  1083. @
  1084. If a response file is expanded, trailing blanks can occur which will be ignored
  1085. here. The same happens if a filename with trailing blanks is enclosed in
  1086. quotes.
  1087.  
  1088. @c
  1089. void modify_filename(name)
  1090.   char *name;
  1091.    {char *p;
  1092.  
  1093.  
  1094.     if((p = strrchr(name, '.')) != NULL)
  1095.        {p++;
  1096.         if(*p && *p != ' ')
  1097.             p++;
  1098.         if(*p && *p != ' ')
  1099.             p++;
  1100.         if(*p != 'w')
  1101.             *p = 'w';
  1102.         else
  1103.             *p = 'x';
  1104.         p++;
  1105.         *p = '\0';
  1106.        }
  1107.     else
  1108.         strcat(name, ".w");
  1109.    }
  1110.  
  1111. @
  1112. @<Global...@>=
  1113. int line_number = 0;
  1114. int column;
  1115.  
  1116. @
  1117. @<Prototypes@>=
  1118. char *get_line(void);
  1119.  
  1120. @
  1121. |get_line()| gets the next line and removes all trailing blanks or tabs.
  1122.  
  1123. @c
  1124. char *get_line(void)
  1125.    {char *p;
  1126.     int i = BUFFER_LENGTH;
  1127.  
  1128.  
  1129.     if((p = fgets(buffer, BUFFER_LENGTH + 1, in)) != NULL)
  1130.        {while(i--)
  1131.            {if(*(p++) == '\n')
  1132.                 break;
  1133.            }@#
  1134.  
  1135.         p--;
  1136.         p--;
  1137.         while((*p == ' ' || *p == '\t') && p >= buffer)
  1138.             p--;
  1139.         *(p + 1) = '\n';
  1140.         *(p + 2) = '\0';@#
  1141.  
  1142.         line_number++;
  1143.         column = 0;
  1144.        }
  1145.     return(p);
  1146.    }
  1147.  
  1148. @
  1149. @<Global...@>=
  1150. char tempbuf[2 * FILE_NAME_LENGTH + 1];
  1151.  
  1152. @
  1153. @<Prototypes@>=
  1154. char *protect_underlines(char *);
  1155.  
  1156. @
  1157. This function is needed for the names of named sections, i.e. file names.
  1158.  
  1159. @c
  1160. char *protect_underlines(p)
  1161.   char *p;
  1162.    {char *q;
  1163.  
  1164.  
  1165.     q = tempbuf;@#
  1166.  
  1167.     do
  1168.        {if(*p == '_')
  1169.             *(q++) = '\\';
  1170.         *(q++) = *p;
  1171.        } while(*(p++));@#
  1172.  
  1173.     return tempbuf;
  1174.    }
  1175.  
  1176. @
  1177. @<Prototypes@>=
  1178. #ifndef __EMX__
  1179. char *_getname(char *);
  1180. #endif
  1181.  
  1182. @
  1183. For Linux and other \UNIX/--systems the function |_getname()| must be
  1184. defined.
  1185.  
  1186. @c
  1187. #ifndef __EMX__
  1188. char *_getname(char *path)
  1189.    {char *p;
  1190.  
  1191.     p = strrchr(path, '/');
  1192.     return p == NULL ? path : (p + 1);
  1193.    }
  1194. #endif
  1195.  
  1196.  
  1197. @* Hints and Tricks.
  1198. Some words are reserved by \.{CWEAVE} you would like to use. Here is a small
  1199. list of them (see the manual for a complete one):
  1200.  
  1201.     \in \.{error}, \.{line}, \.{try}, $\ldots$
  1202.  
  1203. To make a word unreserved write a line
  1204.  
  1205.     \in \.{@@s} \\{ident} \\{x}
  1206.  
  1207. into \.{compiler.w} where \\{ident} is the reserved word.
  1208.  
  1209. Some words you would expect \.{CWEAVE} knows actually are not in its memory:
  1210.  
  1211.     \in \.{va\_arg}, \.{va\_end}, \.{va\_start}, $\ldots$
  1212.  
  1213. To make a word \\{ident1} reserved you should write
  1214.  
  1215.     \in \.{@@s} \\{ident1} \\{ident2}
  1216.  
  1217. into \.{compiler.w}. Now \\{ident1} will behave as \\{ident2}; for example
  1218.  
  1219.     \in \.{@@s va\_decl va\_dcl}
  1220.  
  1221. causes \.{CWEAVE} to treat \.{va\_decl} as it treats \.{va\_dcl}.
  1222.  
  1223. Bear always in mind that \.{CWEAVE} has been developed for use with \UNIX/ and
  1224. not for DOS or OS/2. Weird non-ANSI constructions like
  1225.  
  1226.     \in \&{void \_FAR} |*| \&{\_FARFUNC \_Cdecl} \\{memcpy} $\ldots$
  1227.  
  1228. will cause some, hmmm, troubles if you use the original \.{CWEAVE} program.
  1229. Until now it's also a bit difficult to program for Windows\tm\ or the
  1230. Presentation Manager\tm, because you have to include every structure and
  1231. constant you use in your program manually, which can be a tedious work.
  1232.  
  1233. Do not use the same name for a structure and an instance of it. This means that
  1234. you must avoid things like this:
  1235.  
  1236.     \in \&{struct foo} \\{foo;}
  1237.  
  1238. \.{CWEAVE} would be confused totally. The same applies to all identifiers
  1239. which will be used as reserved and as unreserved words at the same time (This
  1240. usually will not affect identical names of variables and functions. But in
  1241. this case the reader of your program will get confused).
  1242.  
  1243. Most of the \CEE/ constants are written in upper case, and \.{CWEAVE} writes
  1244. them in typewriter type. But some constants like \.{\_Windows} or
  1245. \.{\_\_cplusplus} are mixed or lower case, and \.{CWEAVE} will use italic type
  1246. instead of. Look at \.{compiler.w} again to see a workaround how to get a
  1247. correct output (Note: underline characters are converted to `x' in the
  1248. \TeX\ control string).
  1249.  
  1250. Nested comments are not supported; the program aborts with an error message.
  1251.  
  1252. If you have unbalanced braces due to \.{\#ifdef foo} $\ldots$ \.{\#endif}
  1253. constructions, you can keep \.{c2cweb} and your editor happy if you write a
  1254. \.{/*\{*/} or \.{/*\}*/} command where needed; otherwise memory of \.{CWEAVE}
  1255. can overflow. \.{c2cweb} replaces these commands with the equal \.{CWEB}
  1256. constructions (only defined in this package's modified \.{CWEAVE} version!).
  1257.  
  1258. Another trick with preprocessor conditionals:
  1259.  
  1260.     \in \.{/*@@*/}
  1261.  
  1262.     \in \&{\#ifdef} \.{foo}
  1263.  
  1264.         \in\in \&{int} \\{func1} $\{\,\ldots\,\}$
  1265.  
  1266.     \in \&{\#endif}
  1267.  
  1268.     \in \.{/*@@@@*/}
  1269.  
  1270. Without \.{/*@@*/} the \&{\#endif} instruction would be written into the next
  1271. section.
  1272.  
  1273.  
  1274. @* Index.
  1275.